//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Query Application Block
//===============================================================================

using System;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Common.Instrumentation;
using EntLibContrib.Query.Properties;

namespace EntLibContrib.Query.Instrumentation
{
	/// <summary>
	/// Provides the concrete instrumentation for the logical events raised by a <see cref="QueryInstrumentationProvider"/> object.
	/// </summary>
	[HasInstallableResources]
	[PerformanceCountersDefinition(QueryCountersCategoryName, "QueryCountersCategoryHelpQuery")]
	[EventLogDefinition("Application", EventLogSourceName)]
	public class QueryInstrumentationListener : InstrumentationListener
	{
		#region Constants
		/// <summary>
		/// The name of the event log source.
		/// </summary>
		public const string EventLogSourceName = "Enterprise Library Query";
		/// <summary>
		/// The name of the query counters.
		/// </summary>
		public const string QueryCountersCategoryName = "Enterprise Library Query Counters";
		/// <summary>
		/// Total Query Read Count
		/// </summary>
		public const string QueryTotalReadCountCounterName = "Total Query Read Count";
		/// <summary>
		/// Custom Query Read Count
		/// </summary>
		public const string QueryCustomReadCountCounterName = "Custom Query Read Count";
		/// <summary>
		/// Data Query Read Count
		/// </summary>
		public const string QueryDataReadCountCounterName = "Data Query Read Count";
		/// <summary>
		/// File Query Read Count
		/// </summary>
		public const string QueryFileReadCountCounterName = "File Query Read Count";
		/// <summary>
		/// Service Query Read Count
		/// </summary>
		public const string QueryServiceReadCountCounterName = "Service Query Read Count";
		/// <summary>
		/// Total Query Reads
		/// </summary>
		public const string QueryTotalReadsCounterName = "Total Query Reads";
		/// <summary>
		/// Total Custom Query Reads
		/// </summary>
		public const string QueryCustomReadsCounterName = "Custom Query Reads";
		/// <summary>
		/// Total Data Query Reads
		/// </summary>
		public const string QueryDataReadsCounterName = "Data Query Reads";
		/// <summary>
		/// Total File Query Reads
		/// </summary>
		public const string QueryFileReadsCounterName = "File Query Reads";
		/// <summary>
		/// Total Service Query Reads
		/// </summary>
		public const string QueryServiceReadsCounterName = "Service Query Reads";
		/// <summary>
		/// Total Query Writes
		/// </summary>
		public const string QueryTotalWritesCounterName = "Total Query Writes";
		/// <summary>
		/// Total Custom Query Writes
		/// </summary>
		public const string QueryCustomWritesCounterName = "Custom Query Writes";
		/// <summary>
		/// Total Data Query Writes
		/// </summary>
		public const string QueryDataWritesCounterName = "Data Query Writes";
		/// <summary>
		/// Total File Query Writes
		/// </summary>
		public const string QueryFileWritesCounterName = "File Query Writes";
		/// <summary>
		/// Total Service Query Writes
		/// </summary>
		public const string QueryServiceWritesCounterName = "Service Query Writes";
		/// <summary>
		/// Query Read Count Rate
		/// </summary>
		public const string QueryReadCountRateCounterName = "Query Read Count Rate";
		/// <summary>
		/// Custom Query Read Count Rate
		/// </summary>
		public const string QueryCustomReadCountRateCounterName = "Custom Query Read Count Rate";
		/// <summary>
		/// Data Query Read Count Rate
		/// </summary>
		public const string QueryDataReadCountRateCounterName = "Data Query Read Count Rate";
		/// <summary>
		/// File Query Read Count Rate
		/// </summary>
		public const string QueryFileReadCountRateCounterName = "File Query Read Count Rate";
		/// <summary>
		/// Service Query Read Count Rate
		/// </summary>
		public const string QueryServiceReadCountRateCounterName = "Service Query Read Count Rate";
		/// <summary>
		/// Query Read Rate
		/// </summary>
		public const string QueryReadRateCounterName = "Query Read Rate";
		/// <summary>
		/// Custom Query Read Rate
		/// </summary>
		public const string QueryCustomReadRateCounterName = "Custom Query Read Rate";
		/// <summary>
		/// Data Query Read Rate
		/// </summary>
		public const string QueryDataReadRateCounterName = "Data Query Read Rate";
		/// <summary>
		/// File Query Read Rate
		/// </summary>
		public const string QueryFileReadRateCounterName = "File Query Read Rate";
		/// <summary>
		/// Service Query Read Rate
		/// </summary>
		public const string QueryServiceReadRateCounterName = "Service Query Read Rate";
		/// <summary>
		/// Query Write Rate
		/// </summary>
		public const string QueryWriteRateCounterName = "Query Write Rate";
		/// <summary>
		/// Custom Query Write Rate
		/// </summary>
		public const string QueryCustomWriteRateCounterName = "Custom Query Write Rate";
		/// <summary>
		/// Data Query Write Rate
		/// </summary>
		public const string QueryDataWriteRateCounterName = "Data Query Write Rate";
		/// <summary>
		/// File Query Write Rate
		/// </summary>
		public const string QueryFileWriteRateCounterName = "File Query Write Rate";
		/// <summary>
		/// Service Query Write Rate
		/// </summary>
		public const string QueryServiceWriteRateCounterName = "Service Query Write Rate";
		#endregion

		#region Static Fields
		static EnterpriseLibraryPerformanceCounterFactory factory = new EnterpriseLibraryPerformanceCounterFactory();
		#endregion

		#region Fields
		private string instanceName;
		private IEventLogEntryFormatter eventLogEntryFormatter;
		#endregion

		#region Counters
		[PerformanceCounter(QueryTotalReadCountCounterName, "QueryTotalReadCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryTotalReadCountCounter;

		[PerformanceCounter(QueryCustomReadCountCounterName, "QueryCustomReadCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryCustomReadCountCounter;

		[PerformanceCounter(QueryDataReadCountCounterName, "QueryDataReadCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryDataReadCountCounter;

		[PerformanceCounter(QueryFileReadCountCounterName, "QueryFileReadCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryFileReadCountCounter;

		[PerformanceCounter(QueryServiceReadCountCounterName, "QueryServiceReadCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryServiceReadCountCounter;

		[PerformanceCounter(QueryTotalReadsCounterName, "QueryTotalReadsCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryTotalReadsCounter;

		[PerformanceCounter(QueryCustomReadsCounterName, "QueryCustomReadsCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryCustomReadsCounter;

		[PerformanceCounter(QueryDataReadsCounterName, "QueryDataReadsCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryDataReadsCounter;

		[PerformanceCounter(QueryFileReadsCounterName, "QueryFileReadsCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryFileReadsCounter;

		[PerformanceCounter(QueryServiceReadsCounterName, "QueryServiceReadsCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryServiceReadsCounter;

		[PerformanceCounter(QueryTotalWritesCounterName, "QueryTotalWritesCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryTotalWritesCounter;

		[PerformanceCounter(QueryCustomWritesCounterName, "QueryCustomWritesCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryCustomWritesCounter;

		[PerformanceCounter(QueryDataWritesCounterName, "QueryDataWritesCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryDataWritesCounter;

		[PerformanceCounter(QueryFileWritesCounterName, "QueryFileWritesCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryFileWritesCounter;

		[PerformanceCounter(QueryServiceWritesCounterName, "QueryServiceWritesCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter queryServiceWritesCounter;

		[PerformanceCounter(QueryReadCountRateCounterName, "QueryReadCountRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryReadCountRateCounter;

		[PerformanceCounter(QueryCustomReadCountRateCounterName, "QueryCustomReadCountRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryCustomReadCountRateCounter;

		[PerformanceCounter(QueryDataReadCountRateCounterName, "QueryDataReadCountRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryDataReadCountRateCounter;

		[PerformanceCounter(QueryFileReadCountRateCounterName, "QueryFileReadCountRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryFileReadCountRateCounter;

		[PerformanceCounter(QueryServiceReadCountRateCounterName, "QueryServiceReadCountRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryServiceReadCountRateCounter;

		[PerformanceCounter(QueryReadRateCounterName, "QueryReadRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryReadRateCounter;

		[PerformanceCounter(QueryCustomReadRateCounterName, "QueryCustomReadRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryCustomReadRateCounter;

		[PerformanceCounter(QueryDataReadRateCounterName, "QueryDataReadRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryDataReadRateCounter;

		[PerformanceCounter(QueryFileReadRateCounterName, "QueryFileReadRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryFileReadRateCounter;

		[PerformanceCounter(QueryServiceReadRateCounterName, "QueryServiceReadRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryServiceReadRateCounter;

		[PerformanceCounter(QueryWriteRateCounterName, "QueryWriteRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryWriteRateCounter;

		[PerformanceCounter(QueryCustomWriteRateCounterName, "QueryCustomWriteRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryCustomWriteRateCounter;

		[PerformanceCounter(QueryDataWriteRateCounterName, "QueryDataWriteRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryDataWriteRateCounter;

		[PerformanceCounter(QueryFileWriteRateCounterName, "QueryFileWriteRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryFileWriteRateCounter;

		[PerformanceCounter(QueryServiceWriteRateCounterName, "QueryServiceWriteRateCounterHelpQuery", PerformanceCounterType.RateOfCountsPerSecond32)]
		EnterpriseLibraryPerformanceCounter queryServiceWriteRateCounter;
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new instance of the <see cref="QueryInstrumentationListener"/> class.
		/// </summary>
		/// <param name="instanceName">The name of the <see cref="IQuery"/> instance this instrumentation listener is created for.</param>
		/// <param name="performanceCountersEnabled"><b>true</b> if performance counters should be updated.</param>
		/// <param name="eventLoggingEnabled"><b>true</b> if event log entries should be written.</param>
		/// <param name="wmiEnabled"><b>true</b> if WMI events should be fired.</param>
		/// <param name="applicationInstanceName">The application instance name.</param>
		public QueryInstrumentationListener(string instanceName,
																				bool performanceCountersEnabled,
																				bool eventLoggingEnabled,
																				bool wmiEnabled,
																				string applicationInstanceName)
			: this(instanceName, performanceCountersEnabled, eventLoggingEnabled, wmiEnabled, new AppDomainNameFormatter(applicationInstanceName))
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="QueryInstrumentationListener"/> class.
		/// </summary>
		/// <param name="instanceName">The name of the <see cref="IQuery"/> instance this instrumentation listener is created for.</param>
		/// <param name="performanceCountersEnabled"><b>true</b> if performance counters should be updated.</param>
		/// <param name="eventLoggingEnabled"><b>true</b> if event log entries should be written.</param>
		/// <param name="wmiEnabled"><b>true</b> if WMI events should be fired.</param>
		/// <param name="nameFormatter">The <see cref="IPerformanceCounterNameFormatter"/> that is used to create a unique name for each <see cref="PerformanceCounter"/> instance.</param>
		public QueryInstrumentationListener(string instanceName,
																				bool performanceCountersEnabled,
																				bool eventLoggingEnabled,
																				bool wmiEnabled,
																				IPerformanceCounterNameFormatter nameFormatter)
			: base(new string[] { instanceName }, performanceCountersEnabled, eventLoggingEnabled, wmiEnabled, nameFormatter)
		{
			this.instanceName = instanceName;

			if (EventLoggingEnabled)
				this.eventLogEntryFormatter = new EventLogEntryFormatter(InternalResources.QueryBlockName);
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
		/// Handler for the <see cref="QueryInstrumentationProvider.QueryRead"/> event.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Data for the event.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		[InstrumentationConsumer("QueryRead")]
		public void QueryRead(object sender, QueryReadEventArgs e)
		{
			if (PerformanceCountersEnabled)
			{
				queryTotalReadsCounter.Increment();
				queryReadRateCounter.Increment();
				queryTotalReadCountCounter.IncrementBy(e.ReadCount);
				queryReadCountRateCounter.IncrementBy(e.ReadCount);

				switch(e.QueryType)
				{
					case QueryType.Data:
						queryDataReadsCounter.Increment();
						queryDataReadRateCounter.Increment();
						queryDataReadCountCounter.IncrementBy(e.ReadCount);
						queryDataReadCountRateCounter.IncrementBy(e.ReadCount);
						break;
					case QueryType.File:
						queryFileReadsCounter.Increment();
						queryFileReadRateCounter.Increment();
						queryFileReadCountCounter.IncrementBy(e.ReadCount);
						queryFileReadCountRateCounter.IncrementBy(e.ReadCount);
						break;
					case QueryType.Service:
						queryServiceReadsCounter.Increment();
						queryServiceReadRateCounter.Increment();
						queryServiceReadCountCounter.IncrementBy(e.ReadCount);
						queryServiceReadCountRateCounter.IncrementBy(e.ReadCount);
						break;
					default:
						queryCustomReadsCounter.Increment();
						queryCustomReadRateCounter.Increment();
						queryCustomReadCountCounter.IncrementBy(e.ReadCount);
						queryCustomReadCountRateCounter.IncrementBy(e.ReadCount);
						break;
				}
			}
		}

		/// <summary>
		/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
		/// Handler for the <see cref="QueryInstrumentationProvider.QueryWrite"/> event.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Data for the event.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		[InstrumentationConsumer("QueryWrite")]
		public void QueryWrite(object sender, QueryWriteEventArgs e)
		{
			if (PerformanceCountersEnabled)
			{
				queryTotalWritesCounter.Increment();
				queryWriteRateCounter.Increment();

				switch (e.QueryType)
				{
					case QueryType.Data:
						queryDataWritesCounter.Increment();
						queryDataWriteRateCounter.Increment();
						break;
					case QueryType.File:
						queryFileWritesCounter.Increment();
						queryFileWriteRateCounter.Increment();
						break;
					case QueryType.Service:
						queryServiceWritesCounter.Increment();
						queryServiceWriteRateCounter.Increment();
						break;
					default:
						queryCustomWritesCounter.Increment();
						queryCustomWriteRateCounter.Increment();
						break;
				}
			}
		}

		/// <summary>
		/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
		/// Handler for the <see cref="QueryInstrumentationProvider.QueryFailed"/> event.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Data for the event.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		[InstrumentationConsumer("QueryFailed")]
		public void QueryFailed(object sender, QueryFailureEventArgs e)
		{
			if (e == null)
				throw new ArgumentNullException("e");
				
			if (WmiEnabled)
				FireManagementInstrumentation(new QueryFailureEvent(instanceName, e.ErrorMessage, e.Exception.ToString()));

			if (EventLoggingEnabled)
			{
				string errorMessage = string.Format(InternalResources.Culture, InternalResources.ErrorQueryOperationFailedMessage, instanceName);
				string entryText = eventLogEntryFormatter.GetEntryText(errorMessage, e.Exception, e.ErrorMessage);

				EventLog.WriteEntry(GetEventSourceName(), entryText, EventLogEntryType.Error);
			}
		}
		#endregion

		#region Protected Methods
		/// <summary>
		/// Creates the performance counters to instrument the query events for the specified instance names.
		/// </summary>
		/// <param name="instanceNames">The instance names for the performance counters.</param>
		protected override void CreatePerformanceCounters(string[] instanceNames)
		{
			queryTotalReadCountCounter = factory.CreateCounter(QueryCountersCategoryName, QueryTotalReadCountCounterName, instanceNames);
			queryCustomReadCountCounter = factory.CreateCounter(QueryCountersCategoryName, QueryCustomReadCountCounterName, instanceNames);
			queryDataReadCountCounter = factory.CreateCounter(QueryCountersCategoryName, QueryDataReadCountCounterName, instanceNames);
			queryFileReadCountCounter = factory.CreateCounter(QueryCountersCategoryName, QueryFileReadCountCounterName, instanceNames);
			queryServiceReadCountCounter = factory.CreateCounter(QueryCountersCategoryName, QueryServiceReadCountCounterName, instanceNames);
			queryTotalReadsCounter = factory.CreateCounter(QueryCountersCategoryName, QueryTotalReadsCounterName, instanceNames);
			queryCustomReadsCounter = factory.CreateCounter(QueryCountersCategoryName, QueryCustomReadsCounterName, instanceNames);
			queryDataReadsCounter = factory.CreateCounter(QueryCountersCategoryName, QueryDataReadsCounterName, instanceNames);
			queryFileReadsCounter = factory.CreateCounter(QueryCountersCategoryName, QueryFileReadsCounterName, instanceNames);
			queryServiceReadsCounter = factory.CreateCounter(QueryCountersCategoryName, QueryServiceReadsCounterName, instanceNames);
			queryTotalWritesCounter = factory.CreateCounter(QueryCountersCategoryName, QueryTotalWritesCounterName, instanceNames);
			queryCustomWritesCounter = factory.CreateCounter(QueryCountersCategoryName, QueryCustomWritesCounterName, instanceNames);
			queryDataWritesCounter = factory.CreateCounter(QueryCountersCategoryName, QueryDataWritesCounterName, instanceNames);
			queryFileWritesCounter = factory.CreateCounter(QueryCountersCategoryName, QueryFileWritesCounterName, instanceNames);
			queryServiceWritesCounter = factory.CreateCounter(QueryCountersCategoryName, QueryServiceWritesCounterName, instanceNames);
			queryReadCountRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryReadCountRateCounterName, instanceNames);
			queryCustomReadCountRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryCustomReadCountRateCounterName, instanceNames);
			queryDataReadCountRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryDataReadCountRateCounterName, instanceNames);
			queryFileReadCountRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryFileReadCountRateCounterName, instanceNames);
			queryServiceReadCountRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryServiceReadCountRateCounterName, instanceNames);
			queryReadRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryReadRateCounterName, instanceNames);
			queryCustomReadRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryCustomReadRateCounterName, instanceNames);
			queryDataReadRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryDataReadRateCounterName, instanceNames);
			queryFileReadRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryFileReadRateCounterName, instanceNames);
			queryServiceReadRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryServiceReadRateCounterName, instanceNames);
			queryWriteRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryWriteRateCounterName, instanceNames);
			queryCustomWriteRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryCustomWriteRateCounterName, instanceNames);
			queryDataWriteRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryDataWriteRateCounterName, instanceNames);
			queryFileWriteRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryFileWriteRateCounterName, instanceNames);
			queryServiceWriteRateCounter = factory.CreateCounter(QueryCountersCategoryName, QueryServiceWriteRateCounterName, instanceNames);
		}
		#endregion
	}
}